using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;
using submgr = Microsoft.Dss.Services.SubscriptionManager;
using Emgu.CV;
using Emgu.Util;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System.Drawing;
using System.Windows.Forms;
using capt = Robotics.ImageCapt.Proxy;

namespace Robotics.BgrToGray
{
    [Contract(Contract.Identifier)]
    [DisplayName("BgrToGray")]
    [Description("BgrToGray service (no description provided)")]
    class BgrToGrayService : DsspServiceBase
    {
        /// <summary>
        /// Service state
        /// </summary>
        [ServiceState]
        [InitialStatePartner(Optional = true, ServiceUri = "BgrToGray.Config.xml")]
        BgrToGrayState _state = new BgrToGrayState();

        /// <summary>
        /// Main service port
        /// </summary>
        [ServicePort("/BgrToGray", AllowMultipleInstances = true)]
        BgrToGrayOperations _mainPort = new BgrToGrayOperations();

        /// <summary>
        /// Internal port to update private state.
        /// </summary>
        private BgrToGrayOperations _internalPort = new BgrToGrayOperations();

        [Partner("ImageCapture", Contract = capt.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.UseExistingOrCreate)]
        capt.ImageCaptOperations _imgCaptPort = new capt.ImageCaptOperations();
        capt.ImageCaptOperations _imgCaptNotify = new capt.ImageCaptOperations();

        [SubscriptionManagerPartner]
        submgr.SubscriptionManagerPort _submgrPort = new submgr.SubscriptionManagerPort();

        /// <summary>
        /// Service constructor
        /// </summary>
        public BgrToGrayService(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {
        }

        /// <summary>
        /// Service start
        /// </summary>
        protected override void Start()
        {

            // 
            // Add service specific initialization here
            // 

            base.Start();
            Console.WriteLine("Starting Service...");
            LogInfo("Image BgrToGray starting...");

            // Make sure that we have an initial state!
            if (_state == null)
            {
                _state = new BgrToGrayState();
            }

            SpawnIterator(SubscribeToCapture);

            MainPortInterleave.CombineWith(
                Arbiter.Interleave(
                    new TeardownReceiverGroup(),
                    new ExclusiveReceiverGroup(
                        Arbiter.Receive<NotifyBgrToGray>(true, _internalPort, BgrToGrayDoneHandler),
                        Arbiter.Receive<capt.NotifyImageCapture>(true, _imgCaptNotify, ImageNotificationHandler)
                    ),
                    new ConcurrentReceiverGroup
                        (
                            Arbiter.Receive<ConvBgrToGray>(true, _internalPort, ConvBgrToGrayHandler)
                        )
            ));
        }

        public void ImageNotificationHandler(capt.NotifyImageCapture update)
        {
            Console.WriteLine("Image from camera received");
            LogInfo("Image from camera received");
            Image<Bgr, byte> img = new Image<Bgr, byte>(update.Body.CaptureResImage);
            _internalPort.Post(new ConvBgrToGray(new ConvBgrToGrayRequest(img.Data)));
        }

        // Handler for subscribing to Image Capture Service
        IEnumerator<ITask> SubscribeToCapture()
        {
            Fault fault = null;
            SubscribeResponseType s;

            // Subscribe to the webcam
            capt.Subscribe subscribe = new capt.Subscribe();
            subscribe.NotificationPort = _imgCaptNotify;

            _imgCaptPort.Post(subscribe);

            yield return Arbiter.Choice(
                subscribe.ResponsePort,
                delegate(SubscribeResponseType success)
                { s = success; },
                delegate(Fault f)
                {
                    fault = f;
                }
            );

            if (fault != null)
            {
                LogError(null, "Failed to subscribe to image capture", fault);
                Console.WriteLine("Subscription to image capture failed");
                yield break;
            }
            else
            {
                LogInfo("Subscription to image cature success");
                Console.WriteLine("Subscription to image capture success");
            }

            yield break;

        }

        public void BgrToGrayDoneHandler(NotifyBgrToGray update)
        {
            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            SendNotification(_submgrPort, update);
        }

        /// <summary>
        /// Handles Subscribe messages
        /// </summary>
        /// <param name="subscribe">the subscribe request</param>
        [ServiceHandler]
        public void SubscribeHandler(Subscribe subscribe)
        {
            SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort);
        }

        /// <summary>
        /// Convert BgrToGray Handler
        /// </summary>
        /// <param name="request">ConvBgrToGrayRequest</param>
        /// <returns></returns>
        public void ConvBgrToGrayHandler(ConvBgrToGray request)
        {
            if (_state == null)
                request.ResponsePort.Post(new Fault());
            else
            {
                request.ResponsePort.Post(DefaultUpdateResponseType.Instance);
                Image<Bgr, byte> img = new Image<Bgr, byte>(request.Body.ImageForBgrToGray);
                Image<Gray, byte> gimg = img.Convert<Gray, byte>();

                _internalPort.Post(new NotifyBgrToGray(new BgrToGrayResult(gimg.Data)));

                ImageViewer iv = new ImageViewer();
                iv.Image = gimg;
                iv.ShowDialog();
            }
        }
    }
}


